home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 January / macformat-020.iso / Shareware City / Developers / OutOfPhase1.01Source / OutOfPhase Folder / CompilerRoot.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-10-01  |  28.1 KB  |  855 lines  |  [TEXT/KAHL]

  1. /* CompilerRoot.c */
  2. /*****************************************************************************/
  3. /*                                                                           */
  4. /*    Out Of Phase:  Digital Music Synthesis on General Purpose Computers    */
  5. /*    Copyright (C) 1994  Thomas R. Lawrence                                 */
  6. /*                                                                           */
  7. /*    This program is free software; you can redistribute it and/or modify   */
  8. /*    it under the terms of the GNU General Public License as published by   */
  9. /*    the Free Software Foundation; either version 2 of the License, or      */
  10. /*    (at your option) any later version.                                    */
  11. /*                                                                           */
  12. /*    This program is distributed in the hope that it will be useful,        */
  13. /*    but WITHOUT ANY WARRANTY; without even the implied warranty of         */
  14. /*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          */
  15. /*    GNU General Public License for more details.                           */
  16. /*                                                                           */
  17. /*    You should have received a copy of the GNU General Public License      */
  18. /*    along with this program; if not, write to the Free Software            */
  19. /*    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.              */
  20. /*                                                                           */
  21. /*    Thomas R. Lawrence can be reached at tomlaw@world.std.com.             */
  22. /*                                                                           */
  23. /*****************************************************************************/
  24.  
  25. #include "MiscInfo.h"
  26. #include "Audit.h"
  27. #include "Debug.h"
  28. #include "Definitions.h"
  29.  
  30. #include "CompilerRoot.h"
  31. #include "Memory.h"
  32. #include "CompilerScanner.h"
  33. #include "TrashTracker.h"
  34. #include "CompilerParser.h"
  35. #include "SymbolTable.h"
  36. #include "SymbolTableEntry.h"
  37. #include "ASTExpression.h"
  38. #include "PromotableTypeCheck.h"
  39. #include "SymbolList.h"
  40. #include "CodeCenter.h"
  41. #include "FunctionCode.h"
  42. #include "PeepholeOptimizer.h"
  43. #include "DataMunging.h"
  44. #include "ASTExpressionList.h"
  45.  
  46.  
  47. #define OPAREN "("
  48. #define CPAREN ")"
  49. #define OBRACKET "["
  50. #define CBRACKET "]"
  51.  
  52.  
  53.  
  54.  
  55. /* auxilliary routine for loading keywords */
  56. static void                LoadKeywordsIntoScanner(ScannerRec* Scanner)
  57.     {
  58.         CheckPtrExistence(Scanner);
  59.         AddKeywordToScanner(Scanner,"func",eKeywordFunc);
  60.         AddKeywordToScanner(Scanner,"proto",eKeywordProto);
  61.         AddKeywordToScanner(Scanner,"void",eKeywordVoid);
  62.         AddKeywordToScanner(Scanner,"bool",eKeywordBool);
  63.         AddKeywordToScanner(Scanner,"int",eKeywordInt);
  64.         AddKeywordToScanner(Scanner,"single",eKeywordSingle);
  65.         AddKeywordToScanner(Scanner,"double",eKeywordDouble);
  66.         AddKeywordToScanner(Scanner,"fixed",eKeywordFixed);
  67.         AddKeywordToScanner(Scanner,"boolarray",eKeywordBoolarray);
  68.         AddKeywordToScanner(Scanner,"intarray",eKeywordIntarray);
  69.         AddKeywordToScanner(Scanner,"singlearray",eKeywordSinglearray);
  70.         AddKeywordToScanner(Scanner,"doublearray",eKeywordDoublearray);
  71.         AddKeywordToScanner(Scanner,"fixedarray",eKeywordFixedarray);
  72.         AddKeywordToScanner(Scanner,"var",eKeywordVar);
  73.         AddKeywordToScanner(Scanner,"if",eKeywordIf);
  74.         AddKeywordToScanner(Scanner,"while",eKeywordWhile);
  75.         AddKeywordToScanner(Scanner,"do",eKeywordDo);
  76.         AddKeywordToScanner(Scanner,"until",eKeywordUntil);
  77.         AddKeywordToScanner(Scanner,"set",eKeywordSet);
  78.         AddKeywordToScanner(Scanner,"resize",eKeywordResize);
  79.         AddKeywordToScanner(Scanner,"to",eKeywordTo);
  80.         AddKeywordToScanner(Scanner,"error",eKeywordError);
  81.         AddKeywordToScanner(Scanner,"resumable",eKeywordResumable);
  82.         AddKeywordToScanner(Scanner,"not",eKeywordNot);
  83.         AddKeywordToScanner(Scanner,"sin",eKeywordSin);
  84.         AddKeywordToScanner(Scanner,"cos",eKeywordCos);
  85.         AddKeywordToScanner(Scanner,"tan",eKeywordTan);
  86.         AddKeywordToScanner(Scanner,"asin",eKeywordAsin);
  87.         AddKeywordToScanner(Scanner,"acos",eKeywordAcos);
  88.         AddKeywordToScanner(Scanner,"atan",eKeywordAtan);
  89.         AddKeywordToScanner(Scanner,"ln",eKeywordLn);
  90.         AddKeywordToScanner(Scanner,"exp",eKeywordExp);
  91.         AddKeywordToScanner(Scanner,"sqr",eKeywordSqr);
  92.         AddKeywordToScanner(Scanner,"sqrt",eKeywordSqrt);
  93.         AddKeywordToScanner(Scanner,"abs",eKeywordAbs);
  94.         AddKeywordToScanner(Scanner,"neg",eKeywordNeg);
  95.         AddKeywordToScanner(Scanner,"sign",eKeywordSign);
  96.         AddKeywordToScanner(Scanner,"length",eKeywordLength);
  97.         AddKeywordToScanner(Scanner,"pi",eKeywordPi);
  98.         AddKeywordToScanner(Scanner,"true",eKeywordTrue);
  99.         AddKeywordToScanner(Scanner,"false",eKeywordFalse);
  100.         AddKeywordToScanner(Scanner,"then",eKeywordThen);
  101.         AddKeywordToScanner(Scanner,"else",eKeywordElse);
  102.         AddKeywordToScanner(Scanner,"elseif",eKeywordElseif);
  103.         AddKeywordToScanner(Scanner,"and",eKeywordAnd);
  104.         AddKeywordToScanner(Scanner,"or",eKeywordOr);
  105.         AddKeywordToScanner(Scanner,"xor",eKeywordXor);
  106.         AddKeywordToScanner(Scanner,"div",eKeywordDiv);
  107.         AddKeywordToScanner(Scanner,"mod",eKeywordMod);
  108.         AddKeywordToScanner(Scanner,"getsampleleft",eKeywordGetsampleleft);
  109.         AddKeywordToScanner(Scanner,"getsampleright",eKeywordGetsampleright);
  110.         AddKeywordToScanner(Scanner,"getsample",eKeywordGetsample);
  111.         AddKeywordToScanner(Scanner,"getwavenumframes",eKeywordGetwavenumframes);
  112.         AddKeywordToScanner(Scanner,"getwavenumtables",eKeywordGetwavenumtables);
  113.         AddKeywordToScanner(Scanner,"getwavedata",eKeywordGetwavedata);
  114.     }
  115.  
  116.  
  117.  
  118.  
  119. /* compile a module.  a module is a text block with a series of function definitions. */
  120. /* if compilation succeeds, the functions are added to the CodeCenter object. */
  121. /* the text data is NOT altered. */
  122. CompileErrors            CompileModule(long* ErrorLineNumber, char* TextData, void* Signature,
  123.                                         struct CodeCenterRec* CodeCenter)
  124.     {
  125.         TrashTrackRec*    TheTrashCan;
  126.         ScannerRec*            TheScanner;
  127.         MyBoolean                LoopFlag;
  128.         SymbolTableRec*    TheSymbolTable;
  129.         CompileErrors        FinalErrorThing;
  130.  
  131.         EXECUTE(*ErrorLineNumber = 0x81818181;)
  132.         CheckPtrExistence(TextData);
  133.         CheckPtrExistence(CodeCenter);
  134.         FinalErrorThing = eCompileNoError;
  135.  
  136.         TheTrashCan = NewTrashTracker();
  137.         if (TheTrashCan == NIL)
  138.             {
  139.              NoMemoryPoint1:
  140.                 if (FinalErrorThing != eCompileNoError)
  141.                     {
  142.                         /* since we're aborting, dump any functions we've already created */
  143.                         FlushModulesCompiledFunctions(CodeCenter,Signature);
  144.                     }
  145.                 *ErrorLineNumber = 1;
  146.                 return eCompileOutOfMemory;
  147.             }
  148.  
  149.         TheScanner = NewScanner(TheTrashCan,TextData);
  150.         if (TheScanner == NIL)
  151.             {
  152.              NoMemoryPoint2:
  153.                 DisposeTrashTracker(TheTrashCan);
  154.                 goto NoMemoryPoint1;
  155.             }
  156.         LoadKeywordsIntoScanner(TheScanner);
  157.  
  158.         TheSymbolTable = NewSymbolTable(TheTrashCan);
  159.         if (TheSymbolTable == NIL)
  160.             {
  161.                 goto NoMemoryPoint2;
  162.             }
  163.  
  164.         /* loop until there are no more things to parse */
  165.         LoopFlag = True;
  166.         while (LoopFlag)
  167.             {
  168.                 TokenRec*                Token;
  169.                 long                        InitialLineNumberOfForm;
  170.  
  171.                 Token = GetNextToken(TheScanner);
  172.                 if (Token == NIL)
  173.                     {
  174.                         goto NoMemoryPoint2;
  175.                     }
  176.                 InitialLineNumberOfForm = GetCurrentLineNumber(TheScanner);
  177.                 if (GetTokenType(Token) == eTokenEndOfInput)
  178.                     {
  179.                         /* no more functions to parse, so stop */
  180.                         LoopFlag = False;
  181.                     }
  182.                  else
  183.                     {
  184.                         CompileErrors                Error;
  185.                         SymbolRec*                    SymbolTableEntryForForm;
  186.                         ASTExpressionRec*        FunctionBodyRecord;
  187.  
  188.                         /* parse the function */
  189.                         UngetToken(TheScanner,Token);
  190.                         Error = ParseForm(&SymbolTableEntryForForm,&FunctionBodyRecord,
  191.                             TheScanner,TheSymbolTable,TheTrashCan,ErrorLineNumber);
  192.                         if (Error != eCompileNoError)
  193.                             {
  194.                                 ERROR(*ErrorLineNumber == 0x81818181,PRERR(AllowResume,
  195.                                     "CompileModule:  error line number not set properly"));
  196.                                 FinalErrorThing = Error;
  197.                                 goto ExitErrorPoint;
  198.                             }
  199.                         /* SymbolTableEntryForForm will be the symbol table entry that */
  200.                         /* was added to the symbol table.  FunctionBodyRecord is either */
  201.                         /* an expression for a function or NIL if it was a prototype */
  202.  
  203.                         /* if no error occurred, then generate code */
  204.                         if (FunctionBodyRecord != NIL)
  205.                             {
  206.                                 DataTypes                        ResultingType;
  207.                                 SymbolListRec*            FormalArgumentListScan;
  208.                                 long                                ArgumentIndex;
  209.                                 PcodeRec*                        TheFunctionCode;
  210.                                 long                                StackDepth;
  211.                                 FuncCodeRec*                TheWholeFunctionThing;
  212.                                 long                                ReturnValueLocation;
  213.  
  214.                                 /* only generate code for real functions */
  215.  
  216.                                 /* step 0:  make sure it hasn't been created yet */
  217.                                 if (CodeCenterHaveThisFunction(CodeCenter,GetSymbolName(
  218.                                     SymbolTableEntryForForm),PtrSize(GetSymbolName(
  219.                                     SymbolTableEntryForForm))))
  220.                                     {
  221.                                         FinalErrorThing = eCompileMultiplyDeclaredFunction;
  222.                                         goto ExitErrorPoint;
  223.                                     }
  224.  
  225.                                 /* step 1:  do type checking */
  226.                                 Error = TypeCheckExpression(&ResultingType,FunctionBodyRecord,
  227.                                     ErrorLineNumber,TheTrashCan);
  228.                                 if (Error != eCompileNoError)
  229.                                     {
  230.                                         ERROR(*ErrorLineNumber == 0x81818181,PRERR(AllowResume,
  231.                                             "CompileModule:  error line number not set properly"));
  232.                                         FinalErrorThing = Error;
  233.                                         goto ExitErrorPoint;
  234.                                     }
  235.                                 /* check to see that resulting type matches declared type */
  236.                                 if (!CanRightBeMadeToMatchLeft(GetSymbolFunctionReturnType(
  237.                                     SymbolTableEntryForForm),ResultingType))
  238.                                     {
  239.                                         *ErrorLineNumber = InitialLineNumberOfForm;
  240.                                         FinalErrorThing = eCompileTypeMismatch;
  241.                                         goto ExitErrorPoint;
  242.                                     }
  243.                                 /* if it has to be promoted, then promote it */
  244.                                 if (MustRightBePromotedToLeft(GetSymbolFunctionReturnType(
  245.                                     SymbolTableEntryForForm),ResultingType))
  246.                                     {
  247.                                         ASTExpressionRec*        ReplacementExpr;
  248.  
  249.                                         /* insert promotion operator above expression */
  250.                                         ReplacementExpr = PromoteTheExpression(ResultingType,
  251.                                             GetSymbolFunctionReturnType(SymbolTableEntryForForm),
  252.                                             FunctionBodyRecord,InitialLineNumberOfForm,TheTrashCan);
  253.                                         if (ReplacementExpr == NIL)
  254.                                             {
  255.                                                 *ErrorLineNumber = InitialLineNumberOfForm;
  256.                                                 FinalErrorThing = eCompileOutOfMemory;
  257.                                                 goto ExitErrorPoint;
  258.                                             }
  259.                                         FunctionBodyRecord = ReplacementExpr;
  260.                                         /* sanity check */
  261.                                         Error = TypeCheckExpression(&ResultingType,FunctionBodyRecord,
  262.                                             ErrorLineNumber,TheTrashCan);
  263.                                         ERROR((Error != eCompileNoError),PRERR(ForceAbort,
  264.                                             "CompileModule:  type promotion caused failure"));
  265.                                         ERROR(ResultingType != GetSymbolFunctionReturnType(
  266.                                             SymbolTableEntryForForm),PRERR(ForceAbort,"CompileModule:  "
  267.                                             "after type promotion, types are no longer the same"));
  268.                                     }
  269.  
  270.                                 /* step 2:  do code generation */
  271.                                 /* calling conventions:  */
  272.                                 /*  - leave a space for the return value */
  273.                                 /*  - push the arguments */
  274.                                 /*  - jsr pushes the return address */
  275.                                 /* thus, upon entry, Stack[0] will be the return address */
  276.                                 /* and Stack[-1] will be the rightmost argument */
  277.                                 StackDepth = 1;
  278.                                 ReturnValueLocation = StackDepth; /* remember return value location */
  279.                                 ArgumentIndex = 0;
  280.                                 FormalArgumentListScan = GetSymbolFunctionArgList(SymbolTableEntryForForm);
  281.                                 while (FormalArgumentListScan != NIL)
  282.                                     {
  283.                                         SymbolRec*                    TheFormalArg;
  284.  
  285.                                         TheFormalArg = GetFirstFromSymbolList(FormalArgumentListScan);
  286.                                         StackDepth += 1; /* allocate first */
  287.                                         SetSymbolVariableStackLocation(TheFormalArg,StackDepth); /* remember */
  288.                                         ArgumentIndex += 1;
  289.                                         FormalArgumentListScan = GetRestListFromSymbolList(
  290.                                             FormalArgumentListScan);
  291.                                     }
  292.                                 /* reserve return address spot */
  293.                                 StackDepth += 1;
  294.                                 /* allocate the function code */
  295.                                 TheFunctionCode = NewPcode();
  296.                                 if (TheFunctionCode == NIL)
  297.                                     {
  298.                                         goto NoMemoryPoint2;
  299.                                     }
  300.                                 if (!CodeGenExpression(TheFunctionCode,&StackDepth,FunctionBodyRecord))
  301.                                     {
  302.                                      NoMemoryPoint3:
  303.                                         DisposePcode(TheFunctionCode);
  304.                                         goto NoMemoryPoint2;
  305.                                     }
  306.                                 /* 3 extra words for retval, retaddr, and resultofexpr */
  307.                                 ERROR(StackDepth != ArgumentIndex + 1 + 1 + 1,PRERR(ForceAbort,
  308.                                     "CompileModule:  stack depth error after evaluating function"));
  309.                                 /* move the result to the return slot */
  310.                                 switch (GetExpressionsResultantType(FunctionBodyRecord))
  311.                                     {
  312.                                         default:
  313.                                             EXECUTE(PRERR(ForceAbort,"CompileModule:  unknown type"));
  314.                                             break;
  315.                                         case eBoolean:
  316.                                         case eInteger:
  317.                                         case eFixed:
  318.                                             if (!AddPcodeInstruction(TheFunctionCode,
  319.                                                 epStoreIntegerOnStack,NIL))
  320.                                                 {
  321.                                                     goto NoMemoryPoint3;
  322.                                                 }
  323.                                             break;
  324.                                         case eFloat:
  325.                                             if (!AddPcodeInstruction(TheFunctionCode,
  326.                                                 epStoreFloatOnStack,NIL))
  327.                                                 {
  328.                                                     goto NoMemoryPoint3;
  329.                                                 }
  330.                                             break;
  331.                                         case eDouble:
  332.                                             if (!AddPcodeInstruction(TheFunctionCode,
  333.                                                 epStoreDoubleOnStack,NIL))
  334.                                                 {
  335.                                                     goto NoMemoryPoint3;
  336.                                                 }
  337.                                             break;
  338.                                         case eArrayOfBoolean:
  339.                                         case eArrayOfInteger:
  340.                                         case eArrayOfFloat:
  341.                                         case eArrayOfDouble:
  342.                                         case eArrayOfFixed:
  343.                                             if (!AddPcodeInstruction(TheFunctionCode,
  344.                                                 epStoreArrayOnStack,NIL))
  345.                                                 {
  346.                                                     goto NoMemoryPoint3;
  347.                                                 }
  348.                                             break;
  349.                                     }
  350.                                 /* where to put it?  well, if there are no arguments, then */
  351.                                 /* Stack[0] = the value; Stack[-1] = return address, and */
  352.                                 /* Stack[-2] = the return value */
  353.                                 if (!AddPcodeOperandInteger(TheFunctionCode,
  354.                                     ReturnValueLocation - StackDepth))
  355.                                     {
  356.                                         goto NoMemoryPoint3;
  357.                                     }
  358.                                 /* now pop the result */
  359.                                 if (!AddPcodeInstruction(TheFunctionCode,epStackPop,NIL))
  360.                                     {
  361.                                         goto NoMemoryPoint3;
  362.                                     }
  363.                                 StackDepth -= 1;
  364.                                 /* now, drop all of the parameters from under return address */
  365.                                 if (ArgumentIndex > 0)
  366.                                     {
  367.                                         if (!AddPcodeInstruction(TheFunctionCode,epStackDeallocateUnder,NIL))
  368.                                             {
  369.                                                 goto NoMemoryPoint3;
  370.                                             }
  371.                                         if (!AddPcodeOperandInteger(TheFunctionCode,ArgumentIndex))
  372.                                             {
  373.                                                 goto NoMemoryPoint3;
  374.                                             }
  375.                                         StackDepth -= ArgumentIndex;
  376.                                     }
  377.                                 /* now put the return instruction */
  378.                                 if (!AddPcodeInstruction(TheFunctionCode,epReturnFromSubroutine,NIL))
  379.                                     {
  380.                                         goto NoMemoryPoint3;
  381.                                     }
  382.                                 StackDepth -= 1;
  383.                                 ERROR(StackDepth != 1,PRERR(ForceAbort,
  384.                                     "CompileModule:  stack depth is wrong at end of function"));
  385.  
  386.                                 /* step 2.5:  optimize the code */
  387.                                 OptimizePcode(TheFunctionCode);
  388.  
  389.                                 /* step 3:  create the function and save it away */
  390.                                 TheWholeFunctionThing = NewFunction(GetSymbolName(
  391.                                     SymbolTableEntryForForm),PtrSize(GetSymbolName(
  392.                                     SymbolTableEntryForForm)),GetSymbolFunctionArgList(
  393.                                     SymbolTableEntryForForm),TheFunctionCode,
  394.                                     GetSymbolFunctionReturnType(SymbolTableEntryForForm));
  395.                                 if (TheWholeFunctionThing == NIL)
  396.                                     {
  397.                                         goto NoMemoryPoint3;
  398.                                     }
  399.                                 /* add it to the code center */
  400.                                 if (!AddFunctionToCodeCenter(CodeCenter,TheWholeFunctionThing,Signature))
  401.                                     {
  402.                                      NoMemoryPoint4:
  403.                                         DisposeFunction(TheWholeFunctionThing);
  404.                                         goto NoMemoryPoint3;
  405.                                     }
  406.  
  407.                                 /* wow, all done!  on to the next one */
  408.                             }
  409.                     }
  410.             }
  411.  
  412.      ExitErrorPoint:
  413.         /* clean up the mess */
  414.         DisposeTrashTracker(TheTrashCan);
  415.  
  416.         if (FinalErrorThing != eCompileNoError)
  417.             {
  418.                 /* since we're aborting, dump any functions we've already created */
  419.                 FlushModulesCompiledFunctions(CodeCenter,Signature);
  420.             }
  421.  
  422.         return FinalErrorThing;
  423.     }
  424.  
  425.  
  426.  
  427.  
  428. /* return a null terminated static string describing the error. */
  429. char*                            GetCompileErrorString(CompileErrors Error)
  430.     {
  431.         char*                        S;
  432.  
  433.         switch (Error)
  434.             {
  435.                 default:
  436.                     EXECUTE(PRERR(ForceAbort,"GetCompileErrorString:  unknown error code"));
  437.                     break;
  438.                 case eCompileNoError:
  439.                     EXECUTE(PRERR(ForceAbort,"GetCompileErrorString:  eCompileNoError called"));
  440.                     break;
  441.                 case eCompileOutOfMemory:
  442.                     S = "Out of memory";
  443.                     break;
  444.                 case eCompileExpectedFuncOrProto:
  445.                     S = "Expected 'func' or 'proto'";
  446.                     break;
  447.                 case eCompileExpectedFunc:
  448.                     S = "Expected 'func'";
  449.                     break;
  450.                 case eCompileExpectedIdentifier:
  451.                     S = "Expected identifier";
  452.                     break;
  453.                 case eCompileExpectedOpenParen:
  454.                     S = "Expected '"OPAREN"'";
  455.                     break;
  456.                 case eCompileExpectedCloseParen:
  457.                     S = "Expected '"CPAREN"'";
  458.                     break;
  459.                 case eCompileExpectedColon:
  460.                     S = "Expected ':'";
  461.                     break;
  462.                 case eCompileExpectedSemicolon:
  463.                     S = "Expected ';'";
  464.                     break;
  465.                 case eCompileMultiplyDefinedIdentifier:
  466.                     S = "Identifier has already been used";
  467.                     break;
  468.                 case eCompileExpectedTypeSpecifier:
  469.                     S = "Expected type specification";
  470.                     break;
  471.                 case eCompileExpectedExpressionForm:
  472.                     S = "Expected expression";
  473.                     break;
  474.                 case eCompileExpectedColonEqual:
  475.                     S = "Expected ':='";
  476.                     break;
  477.                 case eCompileExpectedTo:
  478.                     S = "Expected 'to'";
  479.                     break;
  480.                 case eCompileExpectedStringLiteral:
  481.                     S = "Expected string literal";
  482.                     break;
  483.                 case eCompileExpectedResumable:
  484.                     S = "Expected 'resumable'";
  485.                     break;
  486.                 case eCompileExpectedWhile:
  487.                     S = "Expected 'while'";
  488.                     break;
  489.                 case eCompileExpectedDo:
  490.                     S = "Expected 'do'";
  491.                     break;
  492.                 case eCompileExpectedUntil:
  493.                     S = "Expected 'until'";
  494.                     break;
  495.                 case eCompileExpectedOpenParenOrEqual:
  496.                     S = "Expected '"OPAREN"' or '='";
  497.                     break;
  498.                 case eCompileExpectedThen:
  499.                     S = "Expected 'then'";
  500.                     break;
  501.                 case eCompileExpectedWhileOrUntil:
  502.                     S = "Expected 'while' or 'until'";
  503.                     break;
  504.                 case eCompileExpectedCommaOrCloseParen:
  505.                     S = "Expected ',' or '"CPAREN"'";
  506.                     break;
  507.                 case eCompileExpectedElseOrElseIf:
  508.                     S = "Expected 'else' or 'elseif'";
  509.                     break;
  510.                 case eCompileExpectedOperatorOrStatement:
  511.                     S = "Expected operator or statement";
  512.                     break;
  513.                 case eCompileExpectedOperand:
  514.                     S = "Expected operand";
  515.                     break;
  516.                 case eCompileIdentifierNotDeclared:
  517.                     S = "Identifier hasn't been declared";
  518.                     break;
  519.                 case eCompileExpectedRightAssociativeOperator:
  520.                     S = "Expected right associative operator";
  521.                     break;
  522.                 case eCompileExpectedOpenBracket:
  523.                     S = "Expected '"OBRACKET"'";
  524.                     break;
  525.                 case eCompileExpectedCloseBracket:
  526.                     S = "Expected '"CBRACKET"'";
  527.                     break;
  528.                 case eCompileExpectedVariable:
  529.                     S = "Expected variable";
  530.                     break;
  531.                 case eCompileExpectedArrayType:
  532.                     S = "Expected array type";
  533.                     break;
  534.                 case eCompileArraySizeSpecMustBeInteger:
  535.                     S = "Array size specifier must be integer";
  536.                     break;
  537.                 case eCompileTypeMismatch:
  538.                     S = "Type conflict";
  539.                     break;
  540.                 case eCompileInvalidLValue:
  541.                     S = "Invalid l-value";
  542.                     break;
  543.                 case eCompileOperandsMustBeScalar:
  544.                     S = "Operands must be scalar";
  545.                     break;
  546.                 case eCompileOperandsMustBeSequencedScalar:
  547.                     S = "Operands must be sequenced scalar";
  548.                     break;
  549.                 case eCompileOperandsMustBeIntegers:
  550.                     S = "Operands must be an integer";
  551.                     break;
  552.                 case eCompileRightOperandMustBeInteger:
  553.                     S = "Right operand must be an integer";
  554.                     break;
  555.                 case eCompileArraySubscriptMustBeInteger:
  556.                     S = "Array subscript must be an integer";
  557.                     break;
  558.                 case eCompileArrayRequiredForSubscription:
  559.                     S = "Array required for subscription";
  560.                     break;
  561.                 case eCompileDoubleRequiredForExponentiation:
  562.                     S = "Operands for exponentiation must be doubles";
  563.                     break;
  564.                 case eCompileArrayRequiredForResize:
  565.                     S = "Array required for resize";
  566.                     break;
  567.                 case eCompileIntegerRequiredForResize:
  568.                     S = "Integer required resize array size specifier";
  569.                     break;
  570.                 case eCompileConditionalMustBeBoolean:
  571.                     S = "Conditional expression must boolean";
  572.                     break;
  573.                 case eCompileTypeMismatchBetweenThenAndElse:
  574.                     S = "Type conflict between consequent and alternate arms of conditional";
  575.                     break;
  576.                 case eCompileErrorNeedsBooleanArg:
  577.                     S = "Error directive needs boolean argument";
  578.                     break;
  579.                 case eCompileFunctionIdentifierRequired:
  580.                     S = "Function identifier required";
  581.                     break;
  582.                 case eCompileArgumentTypeConflict:
  583.                     S = "Type conflict between formal and actual arguments";
  584.                     break;
  585.                 case eCompileWrongNumberOfArgsToFunction:
  586.                     S = "Wrong number of arguments to function";
  587.                     break;
  588.                 case eCompileCantHaveStringLiteralThere:
  589.                     S = "String literal is not allowed here";
  590.                     break;
  591.                 case eCompileMustBeAVariableIdentifier:
  592.                     S = "Variable identifier required";
  593.                     break;
  594.                 case eCompileOperandMustBeBooleanOrInteger:
  595.                     S = "Operands must be boolean or integer";
  596.                     break;
  597.                 case eCompileOperandMustBeDouble:
  598.                     S = "Operand must be double";
  599.                     break;
  600.                 case eCompileArrayRequiredForGetLength:
  601.                     S = "Array required for length operator";
  602.                     break;
  603.                 case eCompileTypeMismatchInAssignment:
  604.                     S = "Type conflict between l-value and argument";
  605.                     break;
  606.                 case eCompileVoidExpressionIsNotAllowed:
  607.                     S = "Void expression is not allowed";
  608.                     break;
  609.                 case eCompileMultiplyDeclaredFunction:
  610.                     S = "Function name has already been used";
  611.                     break;
  612.                 case eCompilePrototypeCantBeLastThingInExprList:
  613.                     S = "Prototype can't be the last expression in an expression sequence";
  614.                     break;
  615.                 case eCompileInputBeyondEndOfFunction:
  616.                     S = "Input beyond end of expression";
  617.                     break;
  618.                 case eCompileArrayConstructionOnScalarType:
  619.                     S = "Array constructor applied to scalar variable";
  620.                     break;
  621.             }
  622.         return S;
  623.     }
  624.  
  625.  
  626.  
  627.  
  628. /* compile a special function.  a special function has no function header, but is */
  629. /* simply some code to be executed.  the parameters the code is expecting are provided */
  630. /* in the FuncArray[] and NumParams.  the first parameter is deepest beneath the */
  631. /* top of stack.  the TextData is NOT altered.  if an error occurrs, *FunctionOut */
  632. /* will NOT contain a valid object */
  633. CompileErrors            CompileSpecialFunction(FunctionParamRec FuncArray[], long NumParams,
  634.                                         long* ErrorLineNumber, DataTypes* ReturnType, char* TextData,
  635.                                         struct PcodeRec** FunctionOut)
  636.     {
  637.         TrashTrackRec*        TheTrashCan;
  638.         ScannerRec*                TheScanner;
  639.         SymbolTableRec*        TheSymbolTable;
  640.         long                            StackDepth;
  641.         long                            ReturnAddressIndex;
  642.         CompileErrors            Error;
  643.         ASTExpressionRec*    TheExpressionThang;
  644.         ASTExprListRec*        ListOfExpressions;
  645.         PcodeRec*                    TheFunctionCode;
  646.         long                            Scan;
  647.         DataTypes                    ResultingType;
  648.         TokenRec*                    Token;
  649.  
  650.         EXECUTE(*ErrorLineNumber = 0x81818181;)
  651.         CheckPtrExistence(TextData);
  652.  
  653.         TheTrashCan = NewTrashTracker();
  654.         if (TheTrashCan == NIL)
  655.             {
  656.              NoMemoryPoint1:
  657.                 *ErrorLineNumber = 1;
  658.                 return eCompileOutOfMemory;
  659.             }
  660.  
  661.         TheScanner = NewScanner(TheTrashCan,TextData);
  662.         if (TheScanner == NIL)
  663.             {
  664.              NoMemoryPoint2:
  665.                 DisposeTrashTracker(TheTrashCan);
  666.                 goto NoMemoryPoint1;
  667.             }
  668.         LoadKeywordsIntoScanner(TheScanner);
  669.  
  670.         TheSymbolTable = NewSymbolTable(TheTrashCan);
  671.         if (TheSymbolTable == NIL)
  672.             {
  673.                 goto NoMemoryPoint2;
  674.             }
  675.  
  676.         /* build parameters into symbol table */
  677.         StackDepth = 1;
  678.         ReturnAddressIndex = StackDepth;
  679.         for (Scan = 0; Scan < NumParams; Scan += 1)
  680.             {
  681.                 SymbolRec*                TheParameter;
  682.  
  683.                 TheParameter = NewSymbol(TheTrashCan,FuncArray[Scan].ParameterName,
  684.                     StrLen(FuncArray[Scan].ParameterName));
  685.                 if (TheParameter == NIL)
  686.                     {
  687.                         goto NoMemoryPoint2;
  688.                     }
  689.                 SymbolBecomeVariable(TheParameter,FuncArray[Scan].ParameterType);
  690.                 /* allocate stack slot */
  691.                 StackDepth += 1;
  692.                 SetSymbolVariableStackLocation(TheParameter,StackDepth);
  693.                 switch (AddSymbolToTable(TheSymbolTable,TheParameter))
  694.                     {
  695.                         default:
  696.                             EXECUTE(PRERR(ForceAbort,"CompileSpecialFunction:  unknown "
  697.                                 "return code from AddSymbolToTable"));
  698.                             break;
  699.                         case eAddSymbolNoErr:
  700.                             break;
  701.                         case eAddSymbolAlreadyExists:
  702.                             EXECUTE(PRERR(ForceAbort,"CompileSpecialFunction:  "
  703.                                 "eAddSymbolAlreadyExists was returned from AddSymbolToTable"));
  704.                             break;
  705.                         case eAddSymbolNoMemory:
  706.                             goto NoMemoryPoint2;
  707.                     }
  708.             }
  709.         /* fence them off */
  710.         if (!IncrementSymbolTableLevel(TheSymbolTable))
  711.             {
  712.                 goto NoMemoryPoint2;
  713.             }
  714.  
  715.         /* save return address spot */
  716.         /* StackDepth += 1; NO RETURN ADDRESS! */
  717.  
  718.         Error = ParseExprList(&ListOfExpressions,TheScanner,TheSymbolTable,TheTrashCan,
  719.             ErrorLineNumber);
  720.         /* compile the thing */
  721.         if (Error != eCompileNoError)
  722.             {
  723.                 ERROR(*ErrorLineNumber == 0x81818181,PRERR(ForceAbort,
  724.                     "CompileSpecialFunction:  error line number wasn't set properly"));
  725.                 DisposeTrashTracker(TheTrashCan);
  726.                 return Error;
  727.             }
  728.         TheExpressionThang = NewExprSequence(ListOfExpressions,TheTrashCan,
  729.             GetCurrentLineNumber(TheScanner));
  730.         if (TheExpressionThang == NIL)
  731.             {
  732.                 *ErrorLineNumber = GetCurrentLineNumber(TheScanner);
  733.                 DisposeTrashTracker(TheTrashCan);
  734.                 return eCompileOutOfMemory;
  735.             }
  736.  
  737.         /* make sure there is nothing after it */
  738.         Token = GetNextToken(TheScanner);
  739.         if (Token == NIL)
  740.             {
  741.                 goto NoMemoryPoint2;
  742.             }
  743.         if (GetTokenType(Token) != eTokenEndOfInput)
  744.             {
  745.                 *ErrorLineNumber = GetCurrentLineNumber(TheScanner);
  746.                 DisposeTrashTracker(TheTrashCan);
  747.                 return eCompileInputBeyondEndOfFunction;
  748.             }
  749.  
  750.         Error = TypeCheckExpression(&ResultingType,TheExpressionThang,
  751.             ErrorLineNumber,TheTrashCan);
  752.         if (Error != eCompileNoError)
  753.             {
  754.                 ERROR(*ErrorLineNumber == 0x81818181,PRERR(ForceAbort,
  755.                     "CompileSpecialFunction:  error line number wasn't set properly"));
  756.                 DisposeTrashTracker(TheTrashCan);
  757.                 return Error;
  758.             }
  759.  
  760.         TheFunctionCode = NewPcode();
  761.         if (TheFunctionCode == NIL)
  762.             {
  763.                 goto NoMemoryPoint2;
  764.             }
  765.  
  766.         if (!CodeGenExpression(TheFunctionCode,&StackDepth,TheExpressionThang))
  767.             {
  768.              NoMemoryPoint3:
  769.                 DisposePcode(TheFunctionCode);
  770.                 goto NoMemoryPoint2;
  771.             }
  772.  
  773.         ERROR(ReturnType == NIL,PRERR(ForceAbort,
  774.             "CompileSpecialFunction:  ReturnType is NIL"));
  775.         *ReturnType = GetExpressionsResultantType(TheExpressionThang);
  776.  
  777.  
  778.         /* append epilogue */
  779.         /* 1. store result in return slot */
  780.         /* 2. pop result */
  781.         /* note that we do NOT pop the parameters!!! */
  782.  
  783.         /* 2 extra words for retval and resultofexpr */
  784.         ERROR(StackDepth != NumParams + 1 + 1,PRERR(ForceAbort,
  785.             "CompileSpecialFunction:  stack depth error after evaluating function"));
  786.         /* move the result to the return slot */
  787.         switch (GetExpressionsResultantType(TheExpressionThang))
  788.             {
  789.                 default:
  790.                     EXECUTE(PRERR(ForceAbort,"CompileSpecialFunction:  unknown type"));
  791.                     break;
  792.                 case eBoolean:
  793.                 case eInteger:
  794.                 case eFixed:
  795.                     if (!AddPcodeInstruction(TheFunctionCode,epStoreIntegerOnStack,NIL))
  796.                         {
  797.                             goto NoMemoryPoint3;
  798.                         }
  799.                     break;
  800.                 case eFloat:
  801.                     if (!AddPcodeInstruction(TheFunctionCode,epStoreFloatOnStack,NIL))
  802.                         {
  803.                             goto NoMemoryPoint3;
  804.                         }
  805.                     break;
  806.                 case eDouble:
  807.                     if (!AddPcodeInstruction(TheFunctionCode,epStoreDoubleOnStack,NIL))
  808.                         {
  809.                             goto NoMemoryPoint3;
  810.                         }
  811.                     break;
  812.                 case eArrayOfBoolean:
  813.                 case eArrayOfInteger:
  814.                 case eArrayOfFloat:
  815.                 case eArrayOfDouble:
  816.                 case eArrayOfFixed:
  817.                     if (!AddPcodeInstruction(TheFunctionCode,epStoreArrayOnStack,NIL))
  818.                         {
  819.                             goto NoMemoryPoint3;
  820.                         }
  821.                     break;
  822.             }
  823.         /* where to put it?  well, if there are no arguments, then */
  824.         /* Stack[0] = the value; Stack[-1] = return address, and */
  825.         /* Stack[-2] = the return value */
  826.         if (!AddPcodeOperandInteger(TheFunctionCode,ReturnAddressIndex - StackDepth))
  827.             {
  828.                 goto NoMemoryPoint3;
  829.             }
  830.         /* now pop the result */
  831.         if (!AddPcodeInstruction(TheFunctionCode,epStackPop,NIL))
  832.             {
  833.                 goto NoMemoryPoint3;
  834.             }
  835.         StackDepth -= 1;
  836.         /* now put the return instruction */
  837.         if (!AddPcodeInstruction(TheFunctionCode,epReturnFromSubroutine,NIL))
  838.             {
  839.                 goto NoMemoryPoint3;
  840.             }
  841.         /* magically, there is no return address, since the root function call */
  842.         /* is detected by the pcode evaluator and doesn't need a return address */
  843.         ERROR(StackDepth != NumParams + 1,PRERR(ForceAbort,
  844.             "CompileSpecialFunction:  stack depth is wrong at end of function"));
  845.  
  846.         /* optimize stupid things away */
  847.         OptimizePcode(TheFunctionCode);
  848.  
  849.  
  850.         /* it worked, so return the dang thing */
  851.         *FunctionOut = TheFunctionCode;
  852.         DisposeTrashTracker(TheTrashCan);
  853.         return eCompileNoError;
  854.     }
  855.